﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TopDownOperatorPrecedence
{


    public class PEnvironment
    {
        private Dictionary<string, PObject> memberTable;
        public PEnvironment Parent
        {
            get;
            set;
        }

        public PEnvironment(PEnvironment parent = null)
        {
            this.Parent = parent;
            this.memberTable = new Dictionary<string, PObject>();
        }

        public void ClearAll()
        {
            this.memberTable.Clear();
        }

        public void Define(string name, PObject value)
        {
            if (this.memberTable.ContainsKey(name))
            {
                throw new Exception("Name has already been used");
            }

            this.memberTable.Add(name, value);
        }

        public void DefineAtCurrentScope(string name, PObject value)
        {
            this.memberTable[name] = value;
        }

        public void Assign(string name, PObject value)
        {
            PEnvironment environment = this;
            while (environment != null)
            {
                if (environment.memberTable.ContainsKey(name))
                {
                    environment.memberTable[name] = value;
                    break;
                }
                environment = environment.Parent;
            }
            if (environment == null)
            {
                throw new Exception("Name has not been declared");
            }
        }

        public PObject Lookup(string name)
        {
            PEnvironment environment = this;
            while (environment != null)
            {
                if (environment.memberTable.ContainsKey(name))
                {
                    return environment.memberTable[name];
                }
                environment = environment.Parent;
            }
            return null;
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("{");
            PEnvironment current = this;
            string prompt = "current->";
            while (current != null)
            {
                sb.AppendLine(prompt + "{");
                foreach (var pair in current.memberTable)
                {
                    sb.AppendFormat("    {0} : {1},\r\n", pair.Key, pair.Value.ToString());
                }
                sb.AppendLine("  }");
                prompt += "parent->";
                current = current.Parent;
            }
            sb.AppendLine("}");
            return sb.ToString();
        }
    }
}
